package socket;
/**
 *io，服务器接口，插口
 */


import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.SplittableRandom;
import java.util.function.BiFunction;

public class Server {
/*
     * 网络编程接口，是用来进行网络通信的
     * 网络上的两个程序通过一个双向的通信连接实现数据的交换，这个连接的一端称为一个socket。
     * 建立网络通信连接需要一对socket，两个socket之间形成一个管道(通道)，进行信息流的传输(联想IO流中文件和程序之间读写)。

*/

   private  List<PrintWriter> allOut = new ArrayList<>();//创建一个集合，把输出流放里面
    private ServerSocket serverSocket;
    public  Server(){//构造方法
        try {
/* ServerSocket提供的一个重要方法
                    Socket accopt()
                    是阻塞方法*/



            System.out.println("正在启动服务端...");
            serverSocket = new ServerSocket(8088);
            System.out.println("服务端启动完毕...");
        } catch (IOException e) {
            e.printStackTrace();//命令行打印异常信息在程序中出错的位置及原因。
        }
    }
    public void start(){
            try {
                while (true) {
                    System.out.println("等待客户端连接...");
                    Socket socket = serverSocket.accept();
                    System.out.println("一个客户端连接了！");
                    //用任务创建对象，对象实例化一个线程，线程启动
                    ClientHandler handler = new ClientHandler(socket);
                    Thread t = new Thread(handler);
                    t.start();//运行程序
                    }
                } catch(IOException e){
                    e.printStackTrace();//输出错误信息
                }
            }
    public static void main(String[] args) {
        Server server = new Server(); //实例化
        server.start();//调用方法
    }


    //创建一个任务
    private class ClientHandler implements Runnable{
/**
         * 当方法要使用外部传进来的某个参数时，
         * 在当前方法创建一个变量，
         * 再用构造方法来接收，
         * 就可以使用了*/
        private Socket socket;//在当前方法创建一个变量，
        private String host; //记录该客户端的IP地址

        public ClientHandler(Socket socket){//再用构造方法来接收，并赋值
            this.socket = socket;
            host = socket.getInetAddress().getHostAddress();//获取计算机的IP地址
        }
        public void run(){
                PrintWriter pw = null;
            try {
                InputStream in = socket.getInputStream();//input：读取写入
                InputStreamReader isr = new InputStreamReader(in);//字节转换为字符
                BufferedReader br = new BufferedReader(isr);
//              获取输出流给客户端发消息
                OutputStream out = socket.getOutputStream();//输入流
                OutputStreamWriter osw = new OutputStreamWriter(out, StandardCharsets.UTF_8);//转换为字节
                BufferedWriter bw = new BufferedWriter(osw );//缓冲加速（小车）
                 pw = new PrintWriter(bw,true);//按行输入
                synchronized (allOut){
                    //              将该输出流存入共享集合allOut
                    allOut.add(pw);
                }

                /*synchronized (allOut){   //被抢资源。所以锁住，并发线程
                    allOut.add(pw);
                }*/
                System.out.println(host+"上线了，当前在线人数："+allOut.size());

                String message;
                while ((message = br.readLine()) != null) {
                    System.out.println(host+"说：" + message);
                    pw.println(host+"说："+message);
                    synchronized (allOut){
                        //将消息回复给所有客户端
                        for(PrintWriter o:allOut){
                            o.println(host+"说："+message);
                        }
                    }

                }
            } catch (IOException e) {       //readline使用时需要处理IO异常
                e.printStackTrace();
            }finally {
                synchronized (allOut){
                    //处理客户端断开的操作
                    allOut.remove(pw);//将当前客户端输出流从共享集合中删除
                }
                System.out.println(host+"下线了，当前在线人数"+allOut.size());
                try {
                    socket.close();  //关闭scoket时会自动关闭
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
